
#ifndef _CONFIG__CONFIG_H__INCLUDED_
#define _CONFIG__CONFIG_H__INCLUDED_

#include <list>
#include <string>

namespace smartvoice {

class ValueNode
{
public:
	virtual ~ValueNode() {}

	virtual const char*                GetName() const = 0;
	virtual const char*                GetValue() const = 0;

	virtual void                       SetValue(const char* value) = 0;
	virtual void                       SetValue(unsigned int value) = 0;
};

class KeyNode
{
public:
	typedef std::list<KeyNode*>        KeyNodeList;
	typedef std::list<ValueNode*>      ValueList;

public:
	virtual ~KeyNode() {}

	// get the name of the key
	virtual const char*                GetName() const = 0;

	// get the list of subkeys
	virtual KeyNodeList&               GetSubkeys() = 0;
	virtual const KeyNodeList&         GetSubkeys() const = 0;

	// get the subkey by name; if multiple subkeys match the name, the first returned
	//
	// support deep access; e.g.: a single call GetSubkey("level-1/level-2/level-3")
	// to get the subkey named 'level-3' under subkey 'level-2' under subkey 'level-1'
	virtual KeyNode*                   GetSubkey(const char* name) = 0;
	virtual const KeyNode*             GetSubkey(const char* name) const = 0;

	// get the list of values
	virtual ValueList&                 GetValues() = 0;
	virtual const ValueList&           GetValues() const = 0;

	// get the value by name; if multiple values match the name, the first returned
	//
	// support deep access; e.g.: a single call GetSubkey("level-1/level-2/value-1")
	// to get the value named 'value-1' under subkey 'level-2' under subkey 'level-1'
	virtual const char*                GetValue(const char* name) const = 0;

	// add a subkey to the end of the subkeys
	//
	// support deep access; e.g.: a single call AppendSubkey("level-1/level-2/subkey")
	// to add a subkey named 'subkey' under subkey 'level-2' (also create it if it does
	// not exist) under subkey 'level-1' (create it if not exist)
	virtual KeyNode*                   AppendSubkey(const char* name) = 0;

	// append the schema of subkey as a branch of current root
	// a copy of subkey will be made
	virtual KeyNode*                   AppendSubkey(const KeyNode* subkey) = 0;

	// append the subkey as a branch of current root
	// the subkey is inserted into the root directly, caller should
	// maintain the life cycle of the original subkey
	virtual KeyNode*                   SpliceSubkey(KeyNode* subkey) = 0;

	// remove a subkey by name; if multiple subkeys match the name, the first removed;
	// if no subkey match the name, false returned
	virtual bool                       RemoveSubkey(const char* name) = 0;
	virtual bool                       RemoveSubkey(KeyNode* subkey) = 0;

	// release a subkey by name; if multiple subkeys match the name, the first released;
	// if no subkey match the name, NULL returned
	virtual KeyNode*                   ReleaseSubkey(const char* name) = 0;
	virtual KeyNode*                   ReleaseSubkey(KeyNode* subkey) = 0;

	// set a value by name; if multiple values match the name, the first set; if the
	// no value match the name, a value is added with specified value
	virtual void                       SetValue(const char* name, const char* value) = 0;
	virtual void                       SetValue(const char* name, unsigned int value) = 0;

	// add a value to the end of the values
	virtual void                       AppendValue(const char* name, const char* value) = 0;
	virtual void                       AppendValue(const char* name, unsigned int value) = 0;

	// remove a value by name; if multiple values match the name, the first removed;
	// if no value match the name, false returned
	virtual bool                       RemoveValue(const char* name) = 0;

	// recursively clone the KeyNode and all its subkeys and values
	virtual KeyNode*                   Clone() const = 0;
};

KeyNode*	NewConfig(const char* root_name = 0);
KeyNode*	OpenConfig(const char* file);
KeyNode*	OpenMemoryConfig(const char* config);
bool		SaveConfig(const KeyNode*, const char* file);
bool		SaveMemoryConfig(const KeyNode* node, char* memory, int& len);
bool		SaveMemoryConfig(const KeyNode* node, std::string &memory);
void		CloseConfig(KeyNode*);

std::ostream& operator << (std::ostream& os, const KeyNode*);
std::istream& operator >> (std::istream& is, KeyNode*);

} // end namespace smartvoice

#endif // _CONFIG__CONFIG_H__INCLUDED_

